package com.vc.audio;


import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.util.Log;

public class AudioRecorder extends Thread
{
	private static final String TAG = "MVAudio";
	
    //static final int frequency = 8000;   
    int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;   
    static final int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;   
       
    AudioRecord audioRecord = null;
    
    //rec device work status...
    boolean bIsInit = false;
    boolean bIsRecording = false; 
    boolean bIsSending = false; 
    byte[] recBuffer = null;
   
    private int nFrameLen   = 0;  /*coding frame length,bytes*/
    private int recBufSize  = 0; /*device circle buffer lenght,bytes*/ 
    private int nSamplerate = 0;
    private int nChannels   = 0;
    private int nFrameLenInMs = 0;
    
    //for buffer management....
    private int nAviableLen = 0;
    private int nLeftLen = 0;
    byte[] dataBuffer = null;
      

    AudioRecDevCallBack pDevCallBack = null;
      
    Context context;
    
 
    public void SetDevCallBack(AudioRecDevCallBack pCallBack)
    {
    	pDevCallBack = pCallBack;
    }
   
    public int Init(Context mCtxt)
    {
		context = mCtxt;
		

		//AudioServiceConfig();
		
		if(nChannels == 2)
		{
			channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
		}
		else
		{
			channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO; 
		}
		           	
		recBufSize = android.media.AudioRecord.getMinBufferSize(nSamplerate,channelConfiguration, audioEncoding);      	
        	
    	//String logStr = "recBufSize = "+Integer.toString(recBufSize);		
   
    	if (recBufSize == AudioRecord.ERROR_BAD_VALUE || recBufSize == AudioRecord.ERROR )   
        {   
            return 0;    
        }
    	
    	recBufSize  = recBufSize<<1;
        audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,nSamplerate,   
                channelConfiguration,audioEncoding, recBufSize);
        
                
        if(audioRecord.getState() == AudioRecord.STATE_UNINITIALIZED)
      	   return 0;
           
        recBuffer = new byte[recBufSize]; 
        
    	if(null == recBuffer)
    		return 0;
    	   	
        if(nFrameLen <= 0)
        {
        	return 0;
        }
        
        if(recBufSize < nFrameLen)
        { 
            dataBuffer = new byte[nFrameLen];
            
            if(null == dataBuffer)
            	return 0;                       
        }
        
        nAviableLen = nLeftLen = 0;
        
        bIsInit      = true;
    	bIsRecording = false;  
    	
    	return 1;
    }
   
    public int Uninit()
    { 	
    	if(!bIsInit)
    		return 0;
    	
    	audioRecord.release();
    	audioRecord = null;
    	recBuffer   = null;
    	bIsRecording = false;
    	bIsSending   = false;
    	
    	return 1;
    }
    
    public int StartRecord()
    {    
		if(!bIsInit)
			return 0;

		if(bIsRecording)
			return 1;


		bIsRecording = true;  
		bIsSending   = true;

		//start record thread precess...
		start();


		if(audioRecord.getState() == AudioRecord.STATE_UNINITIALIZED)
			return 0;

		audioRecord.startRecording();

		return 1;
    }
        
    /*stop or restore start sending data*/
    public void PauseRecord(boolean  bPause)
    {   
    	if(!bIsInit)
    		return;
    	if(!bIsRecording)
    		return;
    	
    	if(bIsSending == !bPause)
    		return;  
    	

    	

    	//restore sending data.
    	if(bPause)
    	{ 
    		/*
    		audioRecord.stop();    		
    	    */
       	}
    	//stop sending data.
    	else
    	{ 
    	    /*  
        	if(audioRecord.getState() == AudioRecord.STATE_UNINITIALIZED)
         	   return;
        	
    		  audioRecord.startRecording();
    		  
    		*/   		
    	      this.interrupt();    
    	}
    	
    
    	bIsSending = !bPause;
    	
    }
    
    public int StopRecord() 
    {
    	if(!bIsInit)
    		return 0;
    	
    	if(false == bIsRecording)
    		return 1;
       	
    	audioRecord.stop();
    	   
    	//exit thread ...
    	//stop();
    	
    	bIsRecording = false; 	
    	bIsSending = false;
    	   	
    	try {
			join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		      	
    	return 1;
    }
    
    /*set frame length*/
    public int SetRecFormat(int samplerate,int channels,int frmdur)
    {
    	if(true == bIsRecording)
    		return 0;
    	
    	nSamplerate = samplerate;
    	nChannels   = channels;
    	nFrameLenInMs = frmdur;
    	
    	nFrameLen = (nSamplerate/1000)*channels*nFrameLenInMs*2;
    	        	
    	return 1;
    }
    /*get frame length*/
    public int GetFrameLen()
    {   	
    	return nFrameLen;
    }
       
    
    public void run() 
    {   
   	    /*
    	BufferedOutputStream out = null;       
 		try 
        {
        	out = new BufferedOutputStream(new FileOutputStream("/sdcard/winter/recorder.pcm"));
 		} catch (FileNotFoundException e) {
 			// TODO Auto-generated catch block
 			e.printStackTrace();
 		}
 	   */
		  
    	   nAviableLen = nLeftLen = 0;
    	   
    	   android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
    	     
    	   //Log.d(UITAG, "start record.... " );            
            while(bIsRecording) 
            {
            
            	//Log.d(UITAG, "record run");
            	
            	if(!bIsSending)
            	{
            		Log.d(TAG, "AudioRecorder.isSending...");
            		try 
            		{
            			sleep(1000);
            		} catch (InterruptedException e) {
            		}
            	}else{
            		
	               	// read data from record device .
	            	if(recBufSize >= nFrameLen)
	            	{
	            		int nReadResult = audioRecord.read(recBuffer, 0,nFrameLen);           		
	            		
	            		if(nReadResult == nFrameLen)
	            		{
	            			if(null != pDevCallBack)
	 						  pDevCallBack.RecDevDataCallBack(recBuffer, nReadResult);            		         		     				   
	     			    }   
	           		    /*
	           		   try 
	         		   {
	         				  out.write(recBuffer, 0, nFrameLen);
	         				     
	         	       } catch (IOException e) {
	         				  
	         			    	  // TODO Auto-generated catch block
	         				   e.printStackTrace();
	                   }
	      	           */
	            	}
	            	else
	            	{
	            		int nReadResult = audioRecord.read(recBuffer, 0,recBuffer.length);
	            		
	                       		
	            		int offset = 0;
	            		
	            		if(nReadResult == recBuffer.length)
	            		{            			
	            		    nAviableLen = nLeftLen + nReadResult;
	            			
	            			if(nAviableLen >= nFrameLen)
	            			{
	         				    
	            				System.arraycopy(recBuffer,0,dataBuffer,nLeftLen, nFrameLen-nLeftLen);
	            				
	            				if(null != pDevCallBack)
	          						 pDevCallBack.RecDevDataCallBack(dataBuffer, nFrameLen);           				
	            				
	            				//left data in recbuffer...         				           				
	            				nReadResult -= (nFrameLen-nLeftLen);            				           			            			
	            			    offset = nFrameLen-nLeftLen;
	                			
	                			while(nReadResult >= nFrameLen)
	                			{               				
	                                System.arraycopy(recBuffer,offset,dataBuffer,0, nFrameLen);
	                				
	                				if(null != pDevCallBack)
	              						 pDevCallBack.RecDevDataCallBack(dataBuffer, nFrameLen);           				
	                				
	                				//save the left pcm data...
	                			    offset += nFrameLen;
	                			    nReadResult -= nFrameLen;             				                				
	                			}
	                			
	                			//save left data.
	                			nLeftLen = nReadResult;
	                			System.arraycopy(recBuffer,offset,dataBuffer,0, nLeftLen);             				               			
	            				
	            			}
	            			else
	            			{
	            				System.arraycopy(recBuffer,0,dataBuffer,nLeftLen, nReadResult);
	            				nLeftLen += nReadResult;
	            			}           			           		          			
	            		}
	            		
	            	  }
            	} 			  	         
           	     //Thread.yield();    
            }                  
              
    }   
    
}